/*
 *  $Id: Creature.cs 1195 2010-11-19 15:17:06Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;

using AgateLib;
using AgateLib.Geometry;

using Ragima.Helper;

namespace Ragima {

    /// <summary>
    /// Состояние существа
    /// </summary>
    public enum CreatureState {
        Untapped,
        Tapped,
        Delay,
        Offence,
        Defence,
    }

    /// <summary>
    /// Призванное существо
    /// Содержит: ссылка на карту, состояние, список защитников, текущие атака и здоровье
    /// </summary>
    public class Creature: SummonedObject {
        public readonly CreatureCard Card;
        public int Number;
        private CreatureState _state;
        private int _tapTurns;
        public int ForwardStep;
        public readonly List<Creature> Defenders;
        private int _damage, _health;
        private bool _exchangeDamageHealth;
        private bool _instantDeath, _returnToDeck, _returnToNone;
        public bool Eating;
        public byte Alpha;

        private int _turnedAngle, _turnedAngleNeed;

        public Creature(Player owner, CreatureCard card): base(owner) {
            Card = card;
            Summary.SetDefaultAbilities(card);
            AddAffect(new NaturalAffect(card));
            _state = CreatureState.Untapped;
            ForwardStep = 0;
            Defenders = new List<Creature>();
            _exchangeDamageHealth = false;
            _damage = Card.Damage;
            Health = MaxHealth;
            _instantDeath = false;
            _returnToDeck = false;
            Alpha = Constants.MaxAlpha;
            _turnedAngle = 0;
            _turnedAngleNeed = 0;
        }

        public override SummonableCard SummonCard { get { return Card; } }

        public override Race Race {
            get { return Card.Race; }
        }

        public CreatureState State {
            get { return _state; }
            set {
                if (_state == value) return;
                switch (value) {
                    case CreatureState.Untapped:
                        if (Disabled) OnUntap();
                        break;
                    case CreatureState.Tapped:
                        OnTap();
                        break;
                }
                _state = value;
            }
        }
        public bool Disabled {
            get { return _state == CreatureState.Tapped || _state == CreatureState.Delay; }
        }

        public DamageType DmgType {
            get {
                return (Card.AutoDmgType && IsSpirit) || HasFlag<Affects.MagicAttack>() ? DamageType.MagicAttack : DamageType.PhysicalAttack;
            }
        }

        /// <value>
        /// Атака (урон) существа
        /// </value>
        public int Damage {
            get {
                if (HasFlag<Affects.Lifeless>()) return _damage;
                return Math.Max(_damage + (_exchangeDamageHealth ? BonusMaxHealth : BonusDamage), 0);
            }
        }

        /// <value>
        /// Текущее здоровье существа
        /// </value>
        public override int Health {
            get {
                if (HasFlag<Affects.Lifeless>()) return _health;
                return Math.Max(_health + (_exchangeDamageHealth ? BonusDamage : BonusMaxHealth), MinHealth);
            }
            set {
                if (HasFlag<Affects.Lifeless>()) {
                    _health = value;
                    return;
                }
                _health = value - (_exchangeDamageHealth ? BonusDamage : BonusMaxHealth);
            }
        }

        /// <value>
        /// Минимальное здоровье существа
        /// </value>
        public override int MinHealth {
            get {
                if (HasFlag<Affects.Lifeless>()) return 0;
                return _exchangeDamageHealth ? 0 : BonusMinHealth;
            }
        }

        /// <value>
        /// Максимальное здоровье существа
        /// </value>
        public override int MaxHealth {
            get {
                if (HasFlag<Affects.Lifeless>()) return Card.Health;
                return Math.Max(_exchangeDamageHealth ? Card.Damage + BonusDamage : Card.Health + BonusMaxHealth, 0);
            }
        }

        private int BonusDamage {
            get {
                return Summary.GetDamage() + GlobalSummary.GetDamage();
            }
        }
        private int BonusMinHealth {
            get {
                return Summary.GetMinHealth() + GlobalSummary.GetMinHealth();
            }
        }
        private int BonusMaxHealth {
            get {
                return Summary.GetMaxHealth() + GlobalSummary.GetMaxHealth();
            }
        }

        public void ExchangeDamageAndHealth() {
            int temp = _damage;
            _damage = _health;
            _health = temp;
            _exchangeDamageHealth = !_exchangeDamageHealth;
        }

        /// <value>
        /// Является ли объект мертвым (с учетом мгновенной смерти)
        /// </value>
        public override bool IsDeath {
            get { return _instantDeath || base.IsDeath; }
        }

        /// <value>
        /// Мгновенная смерть существа, независимо от бессмертия и реинкарнации
        /// </value>
        public bool IsInstantDeath { get { return _instantDeath; } }

        /// <summary>
        /// Мгновенная смерть существа, независимо от бессмертия и реинкарнации
        /// </summary>
        public override void InstantDeath() {
            _instantDeath = true;
        }
        /// <summary>
        /// Возврат существа в руки хозяина
        /// </summary>
        public override void ReturnToHand() {
            base.ReturnToHand();
            _instantDeath = true;
        }
        /// <summary>
        /// Возврат существа в колоду хозяина
        /// </summary>
        public void ReturnToDeck() {
            _instantDeath = true;
            _returnToDeck = true;
        }

        public void SetNoneCardReturn(bool value) {
            _returnToNone = value;
        }

        /// <summary>
        /// Установка состояния существа после призыва
        /// </summary>
        public void SetSummonState() {
            if (Summary.IsVanguard(this) || GlobalSummary.IsVanguard(this)) {
                State = CreatureState.Untapped;
                // добавление временного эффекта Авангард, если само существо его еще не имеет (для иконки)
                if (!HasFlag<Affects.Vanguard>()) AddAffect(new TimeAffect(8, new Affects.Vanguard()));
            } else
                State = Card.SummonState;
        }

        /// <summary>
        /// Установка состояния существа после перемещения
        /// </summary>
        public void SetMoveState() {
            if (!HasFlag<Affects.MoveTireless>())
                State = CreatureState.Tapped;
        }

        /// <summary>
        /// Установка состояния существа после атаки
        /// </summary>
        public void SetAfterAttackState() {
            if (HasFlag<Affects.Slow>()) {
                State = CreatureState.Untapped;
                AddAffect(new TimeAffect(4, new Affects.SlowAfterAttack()));
            } else if (HasFlag<Affects.Tireless>())
                State = CreatureState.Untapped;
            else
                State = CreatureState.Tapped;
        }

        /// <value>
        /// Куда помещать существо после смерти
        /// </value>
        public CardPlace PlaceAfterDeath {
            get {
                if (_returnToNone) return CardPlace.None;
                if (_returnToHand) return CardPlace.Hands;
                if (_returnToDeck || IsSpirit) return CardPlace.Deck2;
                return Card.PlaceAfterDeath;
            }
        }

        /// <value>
        /// Существо - сосед слева
        /// </value>
        public Creature NeighbourLeft {
            get { return Owner != null && Number > 0 ? Owner.GetCreature(Number-1) : null; }
        }
        /// <value>
        /// Существо - сосед справа
        /// </value>
        public Creature NeighbourRight {
            get { return Owner != null && Number < (Constants.FieldSize-1) ? Owner.GetCreature(Number+1) : null; }
        }

        public void SetTurned(bool turned) {
            _turnedAngleNeed = turned ? 180 : 0;
        }

        public bool NeedTurned {
            get { return _turnedAngle != _turnedAngleNeed; }
        }

        /// <summary>
        /// Отрисовка существа
        /// </summary>
        /// <param name="rect">Прямоугольник, в котором нужно отрисовать существо</param>
        public void Draw(Rectangle rect) {
            Card.SmallPicture.RotationAngleDegrees = _turnedAngle;
            Card.DrawSmall(rect.X, rect.Y, Alpha);
            Card.SmallPicture.RotationAngleDegrees = 0;
            if (NeedTurned || Alpha != Constants.MaxAlpha)
                return;
            switch (State) {
                case CreatureState.Tapped:
                    Data.CardDelay.Color = Color.White;
                    Data.CardDelay.Draw(rect.Location);
                    break;
                case CreatureState.Delay:
                    Data.CardDelay.Color = 0x80FF80.ToColor();
                Data.CardDelay.Draw(rect.Location);
                break;
            }
            AffectIcons.Update(Summary.Icons, rect.Location);
            AffectIcons.Draw();
            Data.Fonts.CardHealth.Draw(rect.X + 2, rect.Y + Constants.SmallCardHeight - 17, string.Format(" {0}/{1} ", Damage, Health));
            DrawHealthChange(rect, true);
        }
        /// <summary>
        /// Обработка существа
        /// </summary>
        public void Process() {
            if (NeedTurned) {
                _turnedAngle += 3;
                if (_turnedAngle >= 360) _turnedAngle = 0;
                if (NeedTurned)
                    return;
                else
                    SetAffectFlash();
            }
            ProcessHealthChange();
        }

        /// <summary>
        /// Расстояние в клетках до указанного места
        /// </summary>
        /// <param name="to">Место</param>
        /// <returns>Расстояние</returns>
        public int DistanceTo(int to) {
            return Math.Abs(Number - to);
        }
        /// <summary>
        /// Расстояние в клетках до указанного существа
        /// </summary>
        /// <param name="other">Существо</param>
        /// <returns>Расстояние</returns>
        public int DistanceTo(Creature other) {
            return Math.Abs(Number - other.Number);
        }

        /// <summary>
        /// Удалить существо
        /// </summary>
        public override void Remove() {
            Owner.RemoveCreature(this, true, !_returnToHand);
        }

        /// <summary>
        /// Поместить карту существа в положенное ей место после смерти у игрока-призывателя
        /// </summary>
        public override void MoveCardAfterDeath() {
            Summoner.CardPutTo(this, PlaceAfterDeath);
        }

        /// <summary>
        /// Переместить существо на указанное место
        /// </summary>
        /// <param name="to">Номер нового места</param>
        public void MoveTo(int to) {
            Owner.MoveCreature(this, to);
        }

        public override void MoveToPlayer(Player newOwner) {
            if (newOwner == Owner) return;
            int place = newOwner.GetNearestFreePlace(Number);
            if (place == -1) return;
            Owner.RemoveCreature(this, false, false);
            Game.Current.Log.Add(Resources.Game.ChangeControl, this, newOwner);
            SetOwner(newOwner);
            newOwner.AddCreature(this, place);
        }

        /// <value>
        /// Парализовано ли существо
        /// </value>
        public bool IsParalysis {
            get { return HasFlag<Affects.Paralysis>(); }
        }

        /// <value>
        /// Может ли существо двигаться
        /// </value>
        public bool CanMove {
            get {
                // проверка паралича
                if (IsParalysis) return false;
                // проверка греха при святости
                if (HasFlag<Affects.Holy>() && HasFlag<Affects.Sinner>()) return false;
                return true;
            }
        }

        /// <summary>
        /// Может ли существо атаковать
        /// </summary>
        public bool CanAttack {
            get { return HasFlag<Affects.Unbind>() || AttackDisablesCount == 0; }
        }

        /// <summary>
        /// Может ли существо отменить атаку
        /// </summary>
        public bool CanResetAttack {
            get { return !HasFlag<Affects.Berserk>(); }
        }

        /// <summary>
        /// Может ли существо сменить атаку
        /// </summary>
        public bool CanChangeAttack {
            get { return (!Disabled && CanAttack) || (State == CreatureState.Offence && CanResetAttack); }
        }

        /// <summary>
        /// Количество запретов атаки
        /// </summary>
        public int AttackDisablesCount {
            get {
                int count = 0;
                // проверка паралича
                if (IsParalysis) count++;
                // проверка запрета атаки
                if (HasFlag<Affects.DisableAttack>()) count++;
                // проверка защитника и отсутствия медлительности
                if (HasFlag<Affects.Guardian>() && !HasFlag<Affects.Slow>()) count++;
                // проверка греха при святости
                if (HasFlag<Affects.Holy>() && HasFlag<Affects.Sinner>()) count++;
                // проверка подводности
                if (IsAquatic && !HasFlag<Affects.Deluge>()) count++;
                return count;
            }
        }

        /// <summary>
        /// Может ли существо блокировать указанное атакующее существо
        /// </summary>
        /// <param name="attacker">Атакующее существо</param>
        /// <returns>true, если может</returns>
        public bool CanBlock(Creature attacker) {
            // проверка паралича
            if (IsParalysis) return false;
            // проверка нападающего и отсутствия медлительности
            if (HasFlag<Affects.Attacker>() && !HasFlag<Affects.Slow>()) return false;
            // проверка греха при святости
            if (HasFlag<Affects.Holy>() && HasFlag<Affects.Sinner>()) return false;
            // получение допустимого расстояния
            int distance = HasFlag<Affects.SlowAfterAttack>() && !HasFlag<Affects.MassBlock>() ? 0 : 1;
            // проверка расстояния
            if (DistanceTo(attacker) > distance) return false;
            // проверка неблокируемости
            if (attacker.HasFlag<Affects.NonBlocked>()) return false;
            // проверка изворотливости
            if (attacker.HasFlag<Affects.Agility>() && !HasFlag<Affects.Guardian>()) return false;
            // проверка полета
            if (attacker.CanFly && !(CanFly || HasFlag<Affects.FlightBlock>())) return false;
            return true;
        }

        /// <value>
        /// Может ли существо летать
        /// </value>
        public bool CanFly {
            get { return HasFlag<Affects.Flight>(); }
        }

        /// <value>
        /// Является ли существо святым и безгрешным
        /// </value>
        public bool IsHoly {
            get { return HasFlag<Affects.Holy>() && !HasFlag<Affects.Sinner>(); }
        }

        /// <value>
        /// Является ли существо подводным
        /// </value>
        public bool IsAquatic {
            get { return HasFlag<Affects.Aquatic>(); }
        }

        public override bool CanUseAbility(AbilityCard ability, bool notice) {
            // проверка паралича
            if (IsParalysis) return false;
            // проверка медлительности
            if (HasFlag<Affects.SlowAfterAttack>()) return false;
            // проверка греха при святости
            if (HasFlag<Affects.Holy>() && HasFlag<Affects.Sinner>() && !ability.AllowInSinner) return false;
            // проверка состояния
            switch (State) {
                case CreatureState.Delay:
                    return false;
                case CreatureState.Tapped:
                    if (!ability.AllowInTapped) return false;
                    break;
                case CreatureState.Offence:
                    if (ability.TapCreatureAfterUse) return false;
                    break;
            }
            return base.CanUseAbility(ability, notice);
        }

        public void UnsetAttack() {
            if (State == CreatureState.Offence) {
                foreach (Creature defender in Defenders) defender.State = CreatureState.Untapped;
                Defenders.Clear();
                State = CreatureState.Untapped;
            }
        }

        public override void OnStartOffencePhase() {
            if (State == CreatureState.Tapped) {
                if (HasFlag<Affects.Idler>() || HasFlag<Affects.Sleeper>())
                    _tapTurns++;
                else
                    State = CreatureState.Untapped;
            }
            base.OnStartOffencePhase();
        }

        public override void OnStartDefencePhase() {
            if (HasFlag<Affects.SlowAfterAttack>()) {
                List<Creature> attackers = new List<Creature>(Owner.Enemy.GetBlockedAttackers(this));
                if (attackers.Count > 0) Owner.SetDefence(this, attackers, true);
            }
            if (State == CreatureState.Tapped) {
                if (HasFlag<Affects.Sleeper>() && _tapTurns > 0 && !HasFlag<Affects.Idler>())
                    State = CreatureState.Untapped;
            }
            base.OnStartDefencePhase();
        }


        public override void OnSummon() {
            base.OnSummon();
            Summary.DoCreatureSummon(this);
            GlobalSummary.DoCreatureSummon(this);
        }

        public override void OnAfterUseAbility(AbilityCard ability, TargetArgs args) {
            base.OnAfterUseAbility(ability, args);
            if (State == CreatureState.Defence) Owner.UnsetDefence(this);
            if (ability.TapCreatureAfterUse && !HasFlag<Affects.AbilityTireless>()) State = CreatureState.Tapped;
        }

        public void OnMove(int from, int to) {
            if (State == CreatureState.Defence) Owner.UnsetDefence(this);
            Summary.DoMove(this, from, to);
            GlobalSummary.DoMove(this, from, to);
        }

        public void OnUntap() {
            Summary.DoUntap(this);
            GlobalSummary.DoUntap(this);
        }

        public void OnTap() {
            _tapTurns = 0;
        }

        public override void OnBattleReady() {
            if (State == CreatureState.Offence) {
                Summary.DoOffenceReady(this);
                GlobalSummary.DoOffenceReady(this);
            } else if (State == CreatureState.Defence) {
                Summary.DoDefenceReady(this);
                GlobalSummary.DoDefenceReady(this);
            }
            Eating = false;
        }

        public void OnHit(AbstractObject target, int damage) {
            if (damage == 0) return;
            Summary.DoHit(this, target, damage);
            GlobalSummary.DoHit(this, target, damage);
        }

        public override void UpdateTarget(Player player) {
            if (Owner != player || !player.IsCurrent || Game.Current.HasTarget) return;
            Game.Current.SetTarget(new CreatureTargetRequest(this));
        }

        public override Region FindRegion() {
            return Owner != null ? Owner.Game.FindRegionBy(this) : null;
        }

        public DamageInfo NewDamage() {
            return NewDamage(Damage);
        }
        public DamageInfo NewDamage(int damage) {
            return new MeleeDamageInfo(this, damage);
        }
    }

}